package org.finesys.system.service.impl;

import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.finesys.common.mp.core.service.impl.BaseServiceImpl;
import org.finesys.common.redis.core.mq.client.RedisMQTemplate;
import org.finesys.system.api.dto.FilterDefinitionDto;
import org.finesys.system.api.dto.PredicateDefinitionDto;
import org.finesys.system.api.dto.RouteConfDto;
import org.finesys.system.api.entity.SysRouteConf;
import org.finesys.system.api.route.mq.RouteMessage;
import org.finesys.system.convert.SysRouteConfConvert;
import org.finesys.system.mapper.SysRouteConfMapper;
import org.finesys.system.service.SysRouteConfService;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@RequiredArgsConstructor
@Slf4j
public class SysRouteConfServiceImpl extends BaseServiceImpl<SysRouteConfMapper, SysRouteConf> implements SysRouteConfService {
    private final RedisMQTemplate redisMQTemplate;

    /**
     * 新增路由信息
     */
    @Override
    public Boolean addRouteConf(SysRouteConf sysRouteConf) {

        //保存路由信息
        this.save(sysRouteConf);
        //通知mq
        this.sendMq();
        return Boolean.TRUE;
    }

     @Override
    public Boolean updateRouteConf(JSONObject json) {
        log.info("--gateway 路由配置修改--");
        try {
            json = json.getJSONObject("router");
            String id = json.getStr("id");
            //update-begin-author:taoyan date:20211025 for: oracle路由网关新增小bug /issues/I4EV2J
            SysRouteConf route;
            if(!StringUtils.hasText(id)){
                route = new SysRouteConf();
            }else{
                route = getById(id);
            }
            //update-end-author:taoyan date:20211025 for: oracle路由网关新增小bug /issues/I4EV2J
            if (ObjectUtils.isEmpty(route)) {
                route = new SysRouteConf();
            }
            route.setRouteId(json.getStr("routeId"));
            route.setName(json.getStr("name"));
            route.setUri(json.getStr("uri"));
            route.setPredicates(json.getStr("predicates"));
            String filters = json.getStr("filters");
                if(!StringUtils.hasText(filters)){
                filters = "[]";
            }
            route.setFilters(filters);
           
            String metadata = json.getStr("metadata");
                if(!StringUtils.hasText(metadata)){
                metadata = "{}";
            }
            route.setMetadata(metadata);
            this.saveOrUpdate(route);
        } catch (Exception e) {
            log.error("路由配置解析失败", e);
            e.printStackTrace();
        }
        //通知mq
        this.sendMq();
        return Boolean.TRUE;
    }

    @Override
    public Boolean updateRouteConf(JSONArray sysRouteConf) {
        //构建路由信息
        List<SysRouteConf> list = sysRouteConf.stream().map(this::convert).collect(Collectors.toList());
        //删除所有路由信息
        baseMapper.delete(Wrappers.emptyWrapper());
        //保存路由信息
        list.stream().forEach(baseMapper::insert);
        //通知mq
        this.sendMq();
        return Boolean.TRUE;
    }

    @Override
    public Boolean deleteRouteConf(Long[] ids) {
        baseMapper.deleteBatchIds(Arrays.asList(ids));
        //通知mq
        this.sendMq();
        return Boolean.TRUE;
    }


    /**
     * 发送mq数据
     */
    private void sendMq() {
        this.redisMQTemplate.send(new RouteMessage(findAllRoute()));
    }

    /**
     * 查询全部路由数据
     */
    public List<RouteConfDto> findAllRoute() {
        List<SysRouteConf> list = findAll();
        return SysRouteConfConvert.INSTANCE.convertList(list);
    }

    /**
     * 构建路由信息
     */
    private SysRouteConf convert(Object value) {
        SysRouteConf conf = new SysRouteConf();
        Map<String, Object> map = (Map<String, Object>) value;
        PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
        propertyMapper.from(map.get(SysRouteConf.Fields.id)).whenNonNull().as(String::valueOf).as(Long::parseLong).to(conf::setId);
        propertyMapper.from(map.get(SysRouteConf.Fields.routeId)).whenNonNull().as(String::valueOf).to(conf::setRouteId);
        propertyMapper.from(map.get(SysRouteConf.Fields.name)).whenNonNull().as(String::valueOf).to(conf::setName);
        propertyMapper.from(map.get(SysRouteConf.Fields.uri)).whenNonNull().as(String::valueOf).as(URI::create).as(String::valueOf).to(conf::setUri);
        propertyMapper.from(map.get(SysRouteConf.Fields.metadata)).whenNonNull().as(String::valueOf).as(v -> JSONUtil.toBean(v, Map.class)).as(JSONUtil::toJsonStr).to(conf::setMetadata);
        propertyMapper.from(map.get(SysRouteConf.Fields.filters)).whenNonNull().as(JSONArray::new).as(v -> v.toList(FilterDefinitionDto.class)).as(JSONUtil::toJsonStr).to(conf::setFilters);
        propertyMapper.from(map.get(SysRouteConf.Fields.predicates)).whenNonNull().as(JSONArray::new).as(v -> v.toList(PredicateDefinitionDto.class)).as(JSONUtil::toJsonStr).to(conf::setPredicates);
        propertyMapper.from(map.get(SysRouteConf.Fields.sortOrder)).whenNonNull().as(String::valueOf).as(Integer::parseInt).to(conf::setSortOrder);
        return conf;
    }
}
